package com.mahjong.server.component.logic.main;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import com.mahjong.server.component.logic.entity.PlayerMahjong;
import com.mahjong.server.component.logic.util.ArrayUtil;
import com.mahjong.server.component.logic.util.LogicConstant;

/**
 * 香港麻将主逻辑
 * @user:   Administrator
 * @author： 游刚
 * @version：1.0
 * @created：Apr 9, 2013
 */

public class KHMahjongLogic {

	//全局变量
	//private KHMahjongAction action = new KHMahjongAction();
	
	//定义每一种胡牌规则
	/**
	 * 七对
	 * <p>可参考方法pairCount</p>
	 * @param pai
	 * @param pm
	 * @return 胡牌返回番数 否则 返回0
	 */
	public int qiDui(String pai,PlayerMahjong pm) {
		String[] shouPai = pm.getShouZhong();
		List<String> list = new LinkedList<String>();
		if (shouPai.length!=13) {
			return 0;
		}
		int count = 0;
		for(int i = 0;i< shouPai.length;i++) {
			if (i<shouPai.length-1) {
				if (shouPai[i].split("_")[0].equals(shouPai[i+1].split("_")[0])) {
					if (i>1 && shouPai[i].split("_")[0].equals(shouPai[i-1].split("_")[0])) {
						continue;
					}
					count++;
					list.add(shouPai[i].split("_")[0]);
				}
			}
		}
		if (count >0 && shouPai[0].split("_")[0].equals(shouPai[1].split("_")[0]) 
				&& shouPai[1].split("_")[0].equals(shouPai[2].split("_")[0])) {
			count --;
		}
		
		if (count != 6 ) {//手牌中没有6个对子
			return 0;
		} else {
			for(String p : shouPai) {
				//不能组成对子的那张牌和打出的牌是一对
				if (!list.contains(p.split("_")[0]) && p.split("_")[0].equals(pai.split("_")[0])) {
					return LogicConstant.QiDui_F;
				}
			}
			return 0;
		}
	}
	
	/**
	 * 平胡
	 * @param pai
	 * @param pm
	 * @return 胡牌返回番数 否则 返回0
	 */
	public int pingHu(String pai,PlayerMahjong pm) {
		try {
			//1.把牌子全部放入一个数组中并进行排序
			String[] allPai = mergerPai(pai, pm);
			
			//2.分析牌
			int pairCount = pairCount(allPai);
			if (pairCount==0) { //2.1 没有对子
				return 0;
			}
			//2.2把同一类牌放入集合中
			List<String> wan = new ArrayList<String>();//萬
			List<String> tong = new ArrayList<String>();//筒
			List<String> tiao = new ArrayList<String>();//条
			List<String> feng = new ArrayList<String>();//东南西北
			List<String> yuan = new ArrayList<String>();//元牌
			String wanNum="",tongNum="",tiaoNum="",fengNum="",yuanNum="";
			for(String p : allPai) {
				String pre = p.substring(0,1);
				if (p.indexOf("萬") != -1) {
					wan.add(p);
				} else if (p.indexOf("筒") != -1){
					tong.add(p);
				} else if (p.indexOf("条") != -1){
					tiao.add(p);
				} else if (pre.equals("1") || pre.equals("2") || pre.equals("3") || pre.equals("4")){
					feng.add(p);
				} else if (pre.equals("5") || pre.equals("6") || pre.equals("7")){
					yuan.add(p);	
				}
			}
			//如果有一张单牌的情况
			if (wan.size()==1 || tong.size()==1 || tiao.size()==1 || feng.size()==1 || yuan.size()==1) {
				return 0;
			}
			//2.3把每一种牌数据取出来
			for (int i = 0; i < wan.size(); i++) {
				wanNum +=wan.get(i).substring(1,2);
			}
			for (int j = 0; j < tong.size(); j++) {
				tongNum +=tong.get(j).substring(1,2);
			}
			for (int k = 0; k < tiao.size(); k++) {
				tiaoNum +=tiao.get(k).substring(1,2);
			}
			for (int m = 0; m < feng.size(); m++) {
				fengNum +=feng.get(m).substring(0,1);
			}
			for (int n = 0; n < yuan.size(); n++) {
				yuanNum +=yuan.get(n).substring(0,1);
			}

			//2.4判断每一类牌的张数对应可胡牌常量数组中是否存在
			if (!canPingHu(wanNum, "PAI_"+wanNum.length())) {
				return 0;
			}
			if (!canPingHu(tongNum, "PAI_"+tongNum.length())) {
				return 0;
			}
			if (!canPingHu(tiaoNum, "PAI_"+tiaoNum.length())) {
				return 0;
			}
			if (!canPingHu(fengNum, "FENG_PAI_"+fengNum.length())) {
				return 0;
			}
			if (!canPingHu(yuanNum, "YUAN_PAI_"+yuanNum.length())) {
				return 0;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return LogicConstant.PingHu_F;
	}
	
	@SuppressWarnings("unchecked")
  private boolean canPingHu(String pais,String fieldName) {
		boolean flag = false;
		try {
			if (pais == null || pais.equals("")) {
				return true;
			}
			//反射获取对象和值
			Class clazz = Class.forName("com.mahjong.server.component.logic.util.LogicConstant");
			Field field = clazz.getField(fieldName);
			String[] fValue = (String[])field.get(null);
			flag = ArrayUtil.isExist(pais, fValue);
		} catch (Exception e) {
		}
		return flag;
	}
	
	/**
	 * 牌中有多少对子:不包括刻子和杠子
	 * @param pais
	 * @return
	 */
	@SuppressWarnings("unchecked")
  private int pairCount(String[] pais) {
		int count = 0;
		Map<String,String> map = new HashMap<String,String>();
		Map<String,String> overlap = new HashMap<String,String>();//重复的对子放进来
		for(String pai: pais) {
			if (map.containsKey(pai.substring(0,2)) && !overlap.containsKey(pai.substring(0,2))) {
				overlap.put(pai.substring(0,2), pai);
				count++;
			}
			map.put(pai.substring(0,2), pai);
			
		}
		//去掉刻子和杠子
		Iterator iter = overlap.keySet().iterator();
		while(iter.hasNext()) {
			String value = iter.next().toString();
			int count2 = 0;
			for(String pai:pais) {
				if (pai.substring(0,2).equals(value.substring(0,2))) {
					count2++;
				}
			}
			if (count2==3 || count2 ==4) {
				count--;
			}
		}
		return count;
	}
	
	/**
	 * 把打出的牌和手中的牌子合并，并且排序
	 * @param pai
	 * @param pm
	 * @return
	 */
	private String [] mergerPai(String pai,PlayerMahjong pm) {
		String[] allPai = new String[pm.getShouZhong().length+1];
		for(int i = 0;i<pm.getShouZhong().length;i++) {
			allPai[i] = pm.getShouZhong()[i];
		}
		allPai[pm.getShouZhong().length] = pai;
		allPai = sortPai(allPai); 
		return allPai;
	}
	
	 /**
	  * 判断是否胡牌
	  * 胡：返回true 不胡：返回false
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	  */
	 public boolean isHuPai(String pai,String[] pais) {
		 //参数 pai是当前出的牌，把每个玩家手里牌取出来做判断
		// TODO
		 return false;
	 }
	 
	 /**
	  * 判断是否听牌
	  * 听：返回true 不听：返回false
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	  */
	 public boolean isTing(String pai,String[] pais) {
		 // TODO
		 return false;
	 }
	 
	 /**
	  * 判断是否吃牌,只判断可不可以吃,至于用哪两张牌去吃由玩家决定
	  * 吃：返回true 不吃：返回false
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	  */
	@SuppressWarnings("unchecked")
  public boolean isChi(String pai,String[] pais) {
		//东南西北中发白直接返回false
		if (pai.indexOf("东")!=-1
				|| pai.indexOf("南")!=-1
				|| pai.indexOf("西")!=-1
				|| pai.indexOf("北")!=-1
				|| pai.indexOf("中")!=-1
				|| pai.indexOf("發")!=-1
				|| pai.indexOf("白")!=-1) {
			return false;
		}
		
		String paiPrefix = pai.split("_")[0];
		Map map = new HashMap();
		//把同一类牌找出来,数字做为key放入map中
		for(String p : pais) {
			if (p.substring(0,1).equals(paiPrefix.substring(0,1))) {
			    map.put(p.split("_")[0].substring(1,2), p);
		    }
		}
		
		if (map == null || map.size()<2) {
		    return false;
		}
		int paiIndex = Integer.parseInt(paiPrefix.substring(1,2));
		if ((map.containsKey((paiIndex+1)+"") && map.containsKey((paiIndex+2)+""))
				|| (map.containsKey((paiIndex-1)+"") && map.containsKey((paiIndex+1)+""))
				|| (map.containsKey((paiIndex-1)+"") && map.containsKey((paiIndex-2)+""))) {
			return true;
		}
 
		return false;
	}
	 
     /**
	  * 判断是否碰牌
	  * 碰：返回true 不碰：返回false
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	 */
	public boolean isPeng(String pai,String[] pais) {
		return isPeng(pai, pais, 2);
	}
	
	private boolean isPeng(String pai,String[] pais,int count) {
		String paiPrefix = pai.split("_")[0];
		int num = 0;
		for(String p : pais) {
			if (p.substring(0,2).equals(paiPrefix)) {
				num++;
		    }
			if (num==count) {
				return true;
			}
		}
		return false;
	}
	 
	 /**
	  * 判断是否杠牌
	  * 杠：返回true 不杠：返回false
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	  */
	 public boolean isGang(String pai,String[] pais) {
		 return isPeng(pai, pais, 3);
	 }
	 
	 /**
	  * 打出一张牌后的处理：判断是否吃、碰、杠、胡,如果满足时执行操作
	  * 托管时会调用,否则由玩家判断
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	  * @return 
	  *      key-used 执行操作使用掉的牌
	  *      key-left 玩家手中还剩下的牌
	  *      key-action 执行的动作 0无动作 1吃 2碰 3杠 3胡
	  */
	 @SuppressWarnings("unchecked")
	 public Map autoHandlePai(String pai,String[] pais) {
		 Map map = new HashMap();
		 // TODO
		 //...
	 
		 map.put("used", null);
		 map.put("left", null);
		 map.put("action", null);
		 return map;
	 }
	 
	 /**
	  * 打出一张牌后的处理：判断是否 胡、杠、碰、吃 （注意检查顺序）
	  * 调用此方法时要先按玩家出牌顺序(开局时掷骰子决定并打上标记)检查玩家是否：胡、杠、碰
	  * @param pai 打出的牌子
	  * @param pais 当前玩家手中的牌
	  * @return 0无动作 1吃 2碰 3杠 3胡
	  */
	 public int checkPai(String pai,String[] pais) {
		// TODO
		 return 0;
	 }
	 
	 /**
	  * 理牌,按顺序排列(从左到右：萬、筒、条、东西南北中发白)
	  * @param pais
	  * @return
	  */
	 public static String[] sortPai(String[] pais) {
		 TreeSet<String> set = new TreeSet<String>();
		 for(String pai : pais) {
			 set.add(pai);
		 }
		 pais = set.toArray(pais);
		 String wan=null,tiong=null,tiao=null,other=null;
		 for(String pai : pais) {
			if (pai.indexOf("萬")!=-1) {
				wan+=pai+",";
				} else if (pai.indexOf("筒")!=-1) {
				tiong+=pai+",";
				} else if (pai.indexOf("条")!=-1) {
				tiao+=pai+",";
				} else {
					other+=pai+",";
		  }
	 }
	 return (wan+tiong+tiao+other).replaceAll("null", "").split(",");
	 }
	 
	 /**
	  * 把String类型pais转换成麻将数组中的索引下标,传给客户端是一个int值
	  * 下标从1开始
	  * @param pais
	  * @return
	  */
	 public int[] convertInt(String[] pais) {
		// TODO
		 return null;
	 }
	 
	/**
	  * 把麻将数组中的索引下标转换成具体的值
	  * @param index 客户端传过来的值
	  * @return
	*/
	public String[] convertString(int[] index) {
		// TODO
		return null;
	}
	 
}
